#!/sbin/sh
#
# A simple Samsung services disabler by Ian Macdonald.
#
# Use this to prime your device after installing TWRP.

DEBUG=true

ZIPFILE=$3
ZIPNAME=${ZIPFILE##*/}
OUTFD=$2

scr_wdth=50

# Detect real $OUTFD
#
if readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null; then
  OUTFD=0
  for FD in $( ls /proc/$$/fd ); do
    if readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null; then
      if ps | grep " 3 $FD " | grep -v grep >/dev/null; then
	OUTFD=$FD
	break
      fi
    fi
  done
fi

ui_print() {
  echo -ne "ui_print $1\n" >> /proc/self/fd/$OUTFD
  echo -ne "ui_print\n" >> /proc/self/fd/$OUTFD
}

debug_print() {
  [ "$DEBUG" = true ] && ui_print "$*"
}

print_full_bar() {
  ui_print "$(printf '%*s\n' $scr_wdth | tr ' ' '=')"
}

print_justified() {
  local str="$1"
  local str_len=${#str}
  local padding_len=$(( ($scr_wdth - $str_len - 2) / 2))
  local ljust="$(printf '%*s' $padding_len)"
  local rjust="$(printf '%*s' $(($padding_len + $str_len % 2)))"

  ui_print "=$ljust$str$rjust="
}

md5() {
  md5sum -b "$1"
}

file_changed() {
  local file="$1"
  local old_md5="$2"
  local new_md5=$( md5 "$file" )

  if [ $new_md5 != $old_md5 ]; then
    debug_print " -     ...modified."
  else
    debug_print " -     ...unchanged."
  fi
}

rm_from_manifest() {
  local service=$1
  local md5
  local i

  # Package path is different on Android 10. Check and adapt.
  #
  [ $major -gt 9 ] && local path_extra='\.hardware'

  for i in /vendor/etc/vintf/manifest.xml \
	   $ANDROID_ROOT/system/etc/vintf/compatibility_matrix.device.xml \
	   /vendor/etc/vintf/manifest/vaultkeeper_manifest.xml; do
    if [ -f $i ]; then
      ui_print " -   Found $i."
      md5=$( md5 $i )
      sed -i -e '/<hal format="hidl">/{N;/<name>vendor\.samsung'"$path_extra"'\.security\.'"$service"'<\/name>/{:loop;N;/<\/hal>/!bloop;d}}' $i
      file_changed $i $md5
    fi
  done
}

disable_fbe() {
  local md5
  local i

  ui_print " - Disabling file-based encryption (FBE) for /data..."

  # S20/N20 range = fstab.exynos990.
  # S10 range = fstab.exynos9820.
  # Note 10 range = fstab.exynos9825.
  # A[124]0 range = fstab.exynos7885.
  # A50 = fstab.exynos9610.
  # Tab A 10.1 range = fstab.exynos7885.
  # Snapdragon devices = fstab.qcom.
  #
  for i in /vendor/etc/fstab.exynos* \
	   /vendor/etc/fstab.qcom*; do
    if [ -f $i ]; then
      ui_print " -   Found $i."
      md5=$( md5 $i )
      # This comments out the offending line and adds an edited one.
      sed -i -e 's/^\([^#].*\)fileencryption=[^,]*\(.*\)$/# &\n\1encryptable\2/g' $i
      file_changed $i $md5
    fi
  done
}

disable_vaultkeeper() {
  local md5
  local i

  ui_print " - Disabling vaultkeeperd..."

  if [ $major -gt 9 ]; then
    # This is Android 10/11: Vaultkeeper has its own init files.
    #
    for i in $ANDROID_ROOT/system/etc/init/vk*.rc /vendor/etc/init/vk*.rc /vendor/etc/init/vaultkeeper*; do
      if [ -f $i ]; then
	ui_print " -   Found $i."
	md5=$( md5 $i )
	sed -i -e 's/^[^#].*$/# &/' $i
	file_changed $i $md5
      fi
    done
  else
    # This is Android 9: Vaultkeeper is started from init.rc.
    #
    sed -i -e 's/^[^#].*vaultkeeper.*$/# &/' \
	-re '/\/system\/bin\/vaultkeeperd/,/^#?$/s/^[^#]*$/#&/' $ANDROID_ROOT/init.rc
  fi

  # Qualcomm devices such as the T860 and T865 need this, otherwise the log
  # will be spammed with messages about failed connections to the Vaultkeeper
  # service.
  #
  rm_from_manifest vaultkeeper

  for i in $ANDROID_ROOT/system /vendor; do
    if [ -f $i/bin/vaultkeeperd ]; then
      ui_print " -   Found $i/bin/vaultkeeperd. Disabling..."
      chmod 0 $i/bin/vaultkeeperd
    fi
  done
}

disable_cass() {
  local md5
  local i

  # The T860 needs this. Otherwise, the log will fill with messages like this:
  #
  # 10-20 03:23:20.501 27757 27757 E CASS: Failed to connect(4)
  # 10-20 03:23:20.501 27757 27757 E CASS: Failed to connect ril daemon(2). Retry cnt(6)
  # The F907B on Android 10 also needs it:
  #
  # 04-05 22:21:23.519  3599  3599 E CASS_DEBUG: VaultKeeper is not ready. try again.
  # 04-05 22:21:23.519  3599  3599 I CASS_DEBUG: Disconnect ril daemon
  # 04-05 22:21:23.519  3599  3599 I CASS_DEBUG: Failed to connect ril daemon(1). Retry cnt(2)
  #
  # As of OneUI 2.5, other devices need it, too; even Exynos.
  #
  ui_print " - Disabling cass..."

  for i in $ANDROID_ROOT/init.rc /vendor/init/cass.rc /vendor/etc/init/cass.rc; do
    if [ -f $i ]; then
      ui_print " -   Found $i. Disabling..."
      md5=$( md5 $i )
      sed -i -e 's/^[^#].*cass.*$/# &/' -re '/\/(system|vendor)\/bin\/cass/,/^#?$/s/^[^#]*$/#&/' $i
      file_changed $i $md5
    fi
  done
}

disable_proca() {
  local md5
  local i

  ui_print " - Disabling process authentication..."

  # G97[035]F = pa_daemon.rc on Android 9; pa_daemon_teegris.rc on Android 10.
  # G977B, N97[05]F, A105F, A505F = pa_daemon_teegris.rc
  # T510 + T515 = pa_daemon_kinibi.rc
  # T860 + T865 = pa_daemon_qsee.rc
  #
  for i in /vendor/etc/init/pa_daemon*.rc; do
    if [ -f $i ]; then
      ui_print " -   Found $i. Disabling..."
      sed -i -e 's/^[^#]/# &/' $i
      file_changed $i $md5
    fi
  done

  rm_from_manifest proca
}

disable_wsm() {
  ui_print " - Disabling wsm..."
  rm_from_manifest wsm
}

disable_recovery_restoration() {
  local r=recovery-from-boot.p
  local found
  local i

  ui_print " - Disabling restoration of stock recovery..."

  for i in $ANDROID_ROOT $ANDROID_ROOT/system; do
    if [ -f $i/$r~ ]; then
	ui_print " -   ...already disabled."
	found=true
	break
    fi

    if [ -f $i/$r ]; then
      ui_print " -   Found $i/$r. Disabling..."
      mv $i/$r $i/$r~

      if [ -f $i/$r~ ]; then
	ui_print " -     ...succeeded."
      else
	ui_print " -     ...failed."
      fi

      found=true
      break
    fi

  done

  [ -z "$found" ] && ui_print " -   Found no stock recovery. Pfft."
}

patch_libbluetooth() {
  [ $major -ne 10 ] && return

  local f=$ANDROID_ROOT/system/lib64/libbluetooth.so
  local tf=/tmp/f

  ui_print " - Bluetooth fix requested via renamed zip."
  ui_print " - Attempting to patch $f..."
  ui_print "     This may take a while."

  if echo $device | grep -E '[GN]9[67][03567][UW0]|F90(0[FN]|7[BN])|T86[05]' >/dev/null; then
    # Snapdragon based devices, such as Tab S6, Fold (5G), USA and Chinese S9/10/N9/10.
    substitute='s/88000054691180522925c81a69000037e0030032/04000014691180522925c81a69000037e0031f2a/'
  else
    substitute='s/c8000034f4031f2af3031f2ae8030032/1f2003d5f4031f2af3031f2ae8031f2a/'
  fi

  xxd -p $f | tr -d '\n ' | sed -e $substitute | xxd -rp > $tf

  if ! cmp $tf $f >/dev/null && [ $(stat -c '%s' $tf) -eq $(stat -c '%s' $f) ]; then
    ui_print " -   Patching succeeded."
    touch -r $f $tf
    chmod 644 $tf
    mv $tf $f
  else
    ui_print " -   Patching failed. No change made."
    rm -f $tf
  fi
}

ui_print " "
print_full_bar
print_justified "Multi-disabler v3.1 for Samsung devices"
print_justified "running Android 9 or later."
print_justified "by Ian Macdonald"
print_full_bar
ui_print " "

os=$(getprop ro.build.version.release)
major=${os%%.*}
bl=$(getprop ro.boot.bootloader)
dp=$(getprop ro.boot.dynamic_partitions)

# Firmware version starts at either 8th or 9th character, depending on length
# of bootloader string (12 or 13).
#
fw=${bl:$((${#bl} - 4)):4}

# Device is first 5 characters of bootloader string.
#
device=${bl:0:$((${#bl} - 8))}
mft=$(getprop ro.product.manufacturer | tr '[A-Z]' '[a-z]')

if [ "$mft" != samsung ]; then
  ui_print " - Device appears not to be made by Samsung."
  fatal=true
elif [ -z "$device" ]; then
  ui_print " - Could not determine device model."
  fatal=true
elif [ $major -lt 9 ]; then
  ui_print " - This software is incompatible with Android $major."
  fatal=true
fi
if [ -n "$fatal" ]; then
  ui_print " - Installation aborted."
  ui_print " "
  exit 1
fi

ui_print " - Detected a $device device with a $fw bootloader."
ui_print " - The environment appears to be Android $major."
ui_print " "

ui_print " - Mounting $ANDROID_ROOT..."
mount $ANDROID_ROOT 2>/dev/null
mount -o remount,rw $ANDROID_ROOT 2>/dev/null

if ! mount | grep $ANDROID_ROOT >/dev/null; then
  ANDROID_ROOT=/system_root
  ui_print " -   Attempt failed. Mounting at $ANDROID_ROOT..."
  mount -o rw $ANDROID_ROOT
  if ! mount | grep $ANDROID_ROOT >/dev/null; then
    ui_print " -   Even that attempt failed. Aborting..."
    exit 2
  fi
fi

ui_print " - Mounting /vendor..."
mount /vendor
mount -o remount,rw /vendor

if ! mount | grep /vendor >/dev/null; then
  ui_print " -   Mount failed. Aborting..."
  exit 3
fi

disable_fbe
disable_recovery_restoration

if [ "$dp" != true ]; then
  disable_vaultkeeper
  disable_proca
  [ $ZIPNAME != ${ZIPNAME/_btfix//} ] && [ $major -gt 9 ] && patch_libbluetooth
fi

if [ $major -gt 9 ]; then
  disable_wsm
  if echo $device | grep -E 'G97([035][FNUW0]|7[BNUW])|N97([05][FNUW0]|6[BNQ0]|1N)|T860|F90(0[FN]|7[BN])|M[23]15F' >/dev/null; then
    disable_cass
  fi
fi

ui_print " - Unmounting /vendor..."
umount /vendor
ui_print " - Unmounting $ANDROID_ROOT..."
umount $ANDROID_ROOT

ui_print " "
ui_print " - Finished."
ui_print " "
